import compose from './compose';
import { Middleware, Store, MiddlewareAPI, Action, Dispatch, StoreEnhancer, StoreCreator, Reducer } from './';
import { AnyAction } from './types';


/*
export default function applyMiddleware(
    ...middlewares:any[]
){
    return function (createStore: any) {
        return function (reducer: any) {
            let store = createStore(reducer);
            //我们在这个地方实现用新的dispatch替换掉老的store.dispatch
            let dispatch: any = undefined;
            const middlewareAPI = {
                getState: store.getState
                , dispatch: (action: any) => dispatch(action)
                // , dispatch //← 不能这么写 因为此时↑dispatch是undefined 而我们马上在下面就会将middlewareAPI作为参数传入middleware 如果发现是一个非引用值 就会直接使用这个值 而不是其引用地址
                // ↑↓等价
                // , dispatch:undefined
            };

            const chain = middlewares.map((middleware: any) => middleware(middlewareAPI));
            dispatch = compose(...chain)(store.dispatch); //上一个函数的输出时下一个函数的输入 就可以使用compose

            return {
                ...store
                ,dispatch
            };
        };
    };
}*/

export function applyMiddleware<Ext, S = any>(
    ...middlewares: Middleware<any, S, any>[]
): StoreEnhancer
export default function applyMiddleware<Ext, S>(
  ...middlewares: Middleware<any, S, any>[]
): StoreEnhancer {
  return (createStore: StoreCreator) => <S, A extends Action>(
    reducer: Reducer<S, A>): Store<S, A> => {
    //'AnyAction' is assignable to the constraint of type 'A'
    // Store<S, A>  dispatch: Dispatch<A>=><T extends A>(action: T) => T
    const store = createStore(reducer);
    let dispatch: Dispatch<AnyAction>;//=><T extends AnyAction>(action: T) => T
    const middlewareAPI: MiddlewareAPI<Dispatch, S> = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    const chain = middlewares.map((middleware: any) => middleware(middlewareAPI));
    dispatch = compose(...chain)(store.dispatch);
    return {
      ...store,
      dispatch
    };
  }
}
/**
 * applyMiddleware
 * StoreEnhancer 是用来接收中间件的函数,返回一个可以增强createStore方法
 *  StoreEnhancerStoreCreator  reducer=>store
 * StoreEnhancer=>StoreEnhancerStoreCreator=>store
 *
 */
